/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include <devices/drv_snd_pangu.h>
#include <yoc/mic.h>
#include <pin_name.h>
#include <media.h>
#include "app_main.h"
#include "app_sys.h"
#include "sona_aef_config.h"

#define TAG "app"

#define SESSION_STATE_IDLE 0
#define SESSION_STATE_START 1
#define SESSION_STATE_WWV 2

#define MAX_WWV_DATA_LEN	0x10000		// 64 K

static uint8_t g_wwv_data[MAX_WWV_DATA_LEN];
extern int g_fct_mode;
static uint8_t g_mic_is_busy = 0;

static void app_clock_alarm_cb(uint8_t clock_id)
{
    LOGI(TAG, "clock_id %d alarm cb handle", clock_id);

    mplayer_start(SOURCE_CLOUD, MEDIA_SYSTEM,
                      "https://cop-image-prod.oss-cn-hangzhou.aliyuncs.com/resource/undefined/"
                      "1577166283488/AudioTest1.mp3", 0, 1);
}

static void media_evt(int type, aui_player_evtid_t evt_id)
{
    //LOGD(TAG, "media_evt type %d,evt_id %d", type, evt_id);

    switch (evt_id) {
        case AUI_PLAYER_EVENT_START:
            event_publish(EVENT_MEDIA_START, NULL);
            break;

        case AUI_PLAYER_EVENT_ERROR:
            event_publish(type == MEDIA_SYSTEM ? EVENT_MEDIA_SYSTEM_ERROR : EVENT_MEDIA_MUSIC_ERROR, NULL);
            if(MEDIA_MUSIC == type) {
                /* media_system doesn't need to play error audio */
                local_audio_play(LOCAL_AUDIO_PLAY_ERR);
            }
            local_audio_finish_check();
            LOGD(TAG, "audio player exit %d", AUI_PLAYER_EVENT_ERROR);
            app_lpm_update();
            break;

        case AUI_PLAYER_EVENT_FINISH:
            event_publish(type == MEDIA_SYSTEM ? EVENT_MEDIA_SYSTEM_FINISH : EVENT_MEDIA_MUSIC_FINISH, NULL);
            local_audio_finish_check();
            LOGD(TAG, "audio player exit %d", AUI_PLAYER_EVENT_FINISH);
            app_lpm_update();
            break;

        default:
            break;
    }

    if (!(type == MEDIA_SYSTEM && evt_id == AUI_PLAYER_EVENT_START)) {
        app_status_update();
    }
}

/* 接收到 MIC 事件 */
static void mic_evt_cb(int source, mic_event_id_t evt_id, void *data, int size)
{
    int        ret;
    static int session_state;
    int type   = *((int *)data);
    int do_wwv = 0;

    if (g_fct_mode) {
        return;
    }

    switch (evt_id) {
        case MIC_EVENT_PCM_DATA:
            if (session_state == SESSION_STATE_IDLE)
                break;

            /* 麦克风数据，推到云端 */
            ret = app_aui_cloud_push_audio(data, size);
            if (ret < 0) {
                /* 数据推送错误 */
                session_state = SESSION_STATE_IDLE;
                LOGE(TAG, "cloud push pcm finish");
                aui_mic_control(MIC_CTRL_STOP_PCM);
                ret = app_aui_cloud_stop(1);
                if (wifi_internet_is_connected() == 0) {
                    LOGE(TAG, "mic evt ntp not synced");
                    local_audio_play(LOCAL_AUDIO_NET_FAIL);
                } else {
                    if (ret < 0) {
                        local_audio_play(LOCAL_AUDIO_SORRY2);
                    }
                }
            }
            break;
        case MIC_EVENT_VAD:
            if (MPLAYER_STATE_MUTE != mplayer_get_state()) {
                app_lpm_update();
            }
            break;
        case MIC_EVENT_SESSION_START:
            if (MPLAYER_STATE_MUTE == mplayer_get_state()) {
                printf("Device is mute\n");
                return;
            }
            LOGD(TAG, "MIC_EVENT_SESSION_START,type= %d", *((int *)data));
            app_lpm_update();
            
            /* 网络检测 */
            if (wifi_internet_is_connected() == 0) {
                LOGE(TAG, "mic_evt net connect failed");
                aui_mic_control(MIC_CTRL_STOP_PCM);
                app_aui_cloud_stop(1);
                if (wifi_is_pairing())
                    local_audio_play(LOCAL_AUDIO_NET_CFG_CONFIG);
                else
                    local_audio_play(LOCAL_AUDIO_NET_FAIL);
                return;
            }

            /* 开始交互 */
            session_state = SESSION_STATE_START;

            if (type & KWS_ID_WWV_MASK) {
                do_wwv        = 1;
                session_state = SESSION_STATE_WWV;
                LOGD(TAG, "wwv process start");
            } else {
                /* play wakeup voice only when wwv is not needed,
                   otherwise do it in the wwv result callback */
                local_wakeup_audio_play(LOCAL_AUDIO_WAKEUP_HELLO);
                app_mic_set_busy(1);
                app_status_update();
            }

            ret = app_aui_cloud_start(do_wwv);
            if (ret != 0) {
                session_state = SESSION_STATE_IDLE;
                return;
            }

            aui_mic_control(MIC_CTRL_START_PCM);

            break;
        case MIC_EVENT_SESSION_STOP:
            LOGD(TAG, "MIC_EVENT_SESSION_STOP");
            app_lpm_update();
            /* 交互结束 */
            if (session_state != SESSION_STATE_IDLE) {
                ret = 0;
                if (session_state == SESSION_STATE_WWV) {
                    ret = app_aui_get_wwv_result(2000);
                    LOGD(TAG, "wwv result %s", ret == 0 ? "success" : "failed");
                }

                if (ret == 0) {
                    app_aui_cloud_stop(0);
                } else {
                    /* wwv rejected or timeout */
                    app_aui_cloud_stop(1);
                }

                aui_mic_control(MIC_CTRL_STOP_PCM);
                session_state = SESSION_STATE_IDLE;
            }

            app_mic_set_busy(0);
            app_status_update();
            break;
        case MIC_EVENT_KWS_DATA:
            if (session_state == SESSION_STATE_WWV) {
                int len;

                len = aui_mic_get_wwv_data(g_wwv_data, MAX_WWV_DATA_LEN);
                if (len > 0) {
                    app_aui_push_wwv_data(g_wwv_data, len);
                } else {
                    aui_mic_control(MIC_CTRL_STOP_PCM);
                    app_aui_cloud_stop(1);
                    LOGW(TAG, "get wwv data failed");
                }
            }

            break;
        default:;
    }
}

/* 闹钟初始化 */
void app_clock_alarm_init(void)
{
#if defined(CONFIG_RTC_EN) && CONFIG_RTC_EN
static int clock_alarm_init_flag = 0;

    if (clock_alarm_init_flag == 0) {
        clock_alarm_init(app_clock_alarm_cb);
        clock_alarm_init_flag = 1;
    }
#endif
}

/*************************************************
 * 音频相关初始化
 *************************************************/
static int app_mic_init(int wwwv_enable)
{
    int ret;
    static voice_adpator_param_t voice_param;
    static mic_param_t param;

    voice_mic_register();

    utask_t *task_mic = utask_new("task_mic", 3 * 1024, 20, AOS_DEFAULT_APP_PRI);
    ret               = aui_mic_start(task_mic, mic_evt_cb);

    memset(&param, 0, sizeof(param));

    param.channels          = 5;
    param.sample_bits       = 16;
    param.rate              = 16000;
    param.sentence_time_ms = 600;
    param.noack_time_ms    = 5000;
    param.max_time_ms      = 10000;
    param.nsmode           = 0; /* 无非线性处理 */
    param.aecmode          = 0; /* 无非线性处理 */
    param.vadmode          = 0; /* 使能VAD */
    param.vadswitch        = 1;
    param.vadfilter        = 2;
    param.vadkws_strategy  = 0;
    param.vadthresh_kws.vad_thresh_sp = -0.6;
    param.vadthresh_kws.vad_thresh_ep = -0.6;
    param.vadthresh_asr.vad_thresh_sp = -0.6;
    param.vadthresh_asr.vad_thresh_ep = -0.6;
    param.wwv_enable        = wwwv_enable;

    voice_param.pcm         = "pcmC0";
    voice_param.cts_ms      = 20;
    voice_param.ipc_mode    = 1;
    voice_param.ai_param    = &param;
    voice_param.ai_param_len = sizeof(mic_param_t);
    param.ext_param1        = &voice_param;


    aui_mic_set_param(&param);

    if (wwwv_enable) {
        app_aui_wwv_init();
    }

    return ret;
}

void app_speaker_mute(int mute)
{
    drv_pinmux_config(PIN_PA_MUTE, PIN_FUNC_GPIO);
    gpio_pin_handle_t pgpio_pin_handle = csi_gpio_pin_initialize(PIN_PA_MUTE, NULL);
    csi_gpio_pin_config_mode(pgpio_pin_handle, GPIO_MODE_PULLNONE);
    csi_gpio_pin_config_direction(pgpio_pin_handle, GPIO_DIRECTION_OUTPUT);
    if(mute) {
        csi_gpio_pin_write(pgpio_pin_handle, false);
    } else {
        csi_gpio_pin_write(pgpio_pin_handle, true);
    }
}
/*************************************************
 * APP的各种测试命令
 *************************************************/
static void cli_reg_cmds(void)
{
    cli_reg_cmd_aui();
    cli_reg_cmd_yvdbg();
    cli_reg_cmd_app();
    cli_reg_cmd_gpio();

    cli_reg_cmd_iperf();
}

/*************************************************
 * 麦克风busy状态
 *************************************************/
void app_mic_set_busy(int busy)
{
    g_mic_is_busy = busy;
}

int app_mic_get_busy(void)
{
    if(MPLAYER_STATE_MUTE == mplayer_get_state()) {
        return 0;
    }
    return g_mic_is_busy;
}

/*************************************************
 * YoC入口函数
 *************************************************/
int main()
{
    extern int  posix_init(void);
    extern void cxx_system_init(void);

    // must call this func when use c++
    posix_init();
    // must call this func when use c++
    cxx_system_init();

    board_base_init();

    yoc_base_init();

    LOGI(TAG, "Build:%s,%s",__DATE__, __TIME__);

    /* 系统事件处理 */
    sys_event_init();

    app_sys_init();

    /* 初始化LED灯 */
    app_status_init();

    /* soft vad 初始化 */
    // app_softvad_init();

    /* 音频数据采集 */
    board_audio_init();

    /* 初始化PWM LED灯 */
#if defined(APP_PWM_EN) && APP_PWM_EN
    app_pwm_led_init();
#endif

    app_lpm_init();

    /* 启动播放器 */
    mplayer_init(4 * 1024, media_evt, 20);

    aui_player_sona_config(sona_aef_config, sona_aef_config_len);

    /* 启动麦克风服务 */
    app_mic_init(1);

    /* 开启功放 */
    app_speaker_mute(0);

    wifi_mode_e mode = app_network_init();

    if (mode != MODE_WIFI_TEST) {
        if (mode != MODE_WIFI_PAIRING &&
            app_sys_get_boot_reason() != BOOT_REASON_WIFI_CONFIG &&
            app_sys_get_boot_reason() != BOOT_REASON_WAKE_STANDBY) {
                local_audio_play(LOCAL_AUDIO_STARTING);
            }
#if defined(APP_FOTA_EN) && APP_FOTA_EN
        app_fota_init();
#endif

        if (g_fct_mode) {
            fct_case_init();
        }

        /* 交互系统初始化 */
        app_aui_nlp_init();
        app_text_cmd_init();
    }

    /* 按键初始化 */
    app_button_init();

    /* LED状态初始化 */
    app_set_led_state(LED_TURN_OFF);

    /* 命令行测试命令 */
    cli_reg_cmds();

    return 0;
}
